/*
 *
 *  Copyright (C) 2010 Tal Eisenberg
 *
 *  This program is free software: you can redistribute it and/or modify
 *  it under the terms of the GNU General Public License as published by
 *  the Free Software Foundation, either version 3 of the License, or
 *  (at your option) any later version.
 *
 *  This program is distributed in the hope that it will be useful,
 *  but WITHOUT ANY WARRANTY; without even the implied warranty of
 *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
 *  GNU General Public License for more details.
 *
 *  You should have received a copy of the GNU General Public License
 *  along with this program.  If not, see <http://www.gnu.org/licenses/>.
 */

package fork;

import java.io.IOException;
import java.io.OutputStream;
import java.io.PrintStream;
import java.util.List;
import tal.drivechain.chain.AbortChainException;
import tal.drivechain.chain.Chain;
import tal.drivechain.chain.script.ScriptCommand;
import tal.drivechain.chain.shell.DriveShell;
import tal.drivechain.plugin.Channel;
import tal.drivechain.plugin.Module;
import tal.drivechain.system.Globals;
import tal.drivechain.variable.types.DataType;
import tal.drivechain.variable.SetProperty;
import tal.drivechain.variable.Variable;

/**
 *
 * @author eisental
 */
public class Shell extends Module {
    DriveShell shell;
    private Variable curChain = new Variable("curChain", DataType.STRING, null, true);

    @Override
    public void setupProperties() throws IllegalArgumentException, AbortChainException {
        shell = new DriveShell(new PrintStream(new VarOutputStream()));

        setActiveChain(props.getProperty("activeChain"), null);
    }

    public void setActiveChain(Object value, SetProperty.Flag flag) {
        if (value==null)
            shell.setActiveChain(Globals.getRootChain());
        else {
            Chain c = Globals.findChain((String)value, shell.getActiveChain());
            if (!c.equals(shell.getActiveChain()))
                shell.setActiveChain(c);
        }
        
        chainUpdated();
    } public Object getActiveChain() { return shell.getActiveChain().getPath(); }

    @Override
    protected void msgReceived(Variable in, long timestamp, Channel channel) {
        if (channel==Channel.CHAIN && in.getDataType().matches(DataType.STRING)) {
            try {
                String command = (String)in.getValue(this);
                ScriptCommand[] commands = DriveShell.parseCommand(command);
                for (ScriptCommand c : commands)
                    shell.runCommand(c);
                chainUpdated();
            } catch (IllegalArgumentException e) {
                log(e.getMessage(), MSG.ERROR);
            }
        }
    }

    @Override
    public void start() {
        super.start();
        shell.greet();
    }

    public void greet() {
        shell.greet();
    }

    private void chainUpdated() {
        if (isRunning() && !shell.getActiveChain().getPath().equals((String)curChain.getInternalValue())) {
            curChain.setValue(shell.getActiveChain().getPath(), true);
            sendToOutputs(curChain, -1);
        }
    }

    class VarOutputStream extends OutputStream {
        Variable out = new Variable("shell", DataType.STRING, "", true);
        StringBuffer outbuf = new StringBuffer();

        @Override
        public void write(int b) throws IOException {
            if (b=='\n') this.flush();
            else outbuf.append((char)b);
        }

        @Override
        public void flush() throws IOException {
            out.setValue(outbuf.toString(), true);
            outbuf = new StringBuffer();
            if (isRunning())
                sendToOutputs(out, -1);
        }
    }
}
